﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Text.RegularExpressions;

namespace Bing.Toolkit.Data
{
    [Serializable]
    public class KeyValueObject
    {
        protected Dictionary<String, Object> keyValueCollection = new Dictionary<string, object>();
        /// <summary>
        /// KeyValue键值对的数量
        /// </summary>
        public int Count 
        { 
            get { return keyValueCollection.Count; } 
        }
        /// <summary>
        /// 返回所有的Key
        /// </summary>
        public Dictionary<string, object>.KeyCollection Keys 
        { 
            get { return keyValueCollection.Keys; } 
        }
        /// <summary>
        /// 返回所有的Value
        /// </summary>
        public Dictionary<string, object>.ValueCollection Values 
        { 
            get { return keyValueCollection.Values; } 
        }

        /// <summary>
        /// 默认构造函数
        /// </summary>
        public KeyValueObject() { }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dictionary"></param>
        public KeyValueObject(Dictionary<String, Object> dictionary) 
        {
            dictionary.ToList().ForEach(o => keyValueCollection.Add(o.Key, o.Value));
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="list"></param>
        public KeyValueObject(List<KeyValuePair<string, object>> list)
        {
            foreach (var entry in list)
            {
                keyValueCollection.Add(entry.Key, entry.Value);
            }
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="collection"></param>
        public KeyValueObject(NameValueCollection collection)
        {
            foreach (string key in collection.Keys)
            {
                keyValueCollection.Add(key, collection[key]);
            }
        }
        /// <summary>
        /// 根据键获取字符串
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public string GetString(string key)
        {
            return this[key].ToString();
        }
        /// <summary>
        /// 根据键获取值，这是一个范型方法，可以把值自动转换想要的类型。
        /// </summary>
        /// <typeparam name="T">要转换的类型</typeparam>
        /// <param name="key">Key</param>
        /// <returns>Value</returns>
        public T Get<T>(string key)
        {
            if (!keyValueCollection.ContainsKey(key))
                return default(T);
            else
                return (T)(Convert.ChangeType(keyValueCollection[key], typeof(T)));
        }
        /// <summary>
        /// 添加键值对
        /// </summary>
        /// <param name="key">Key</param>
        /// <param name="value">Value</param>
        public void Set(string key, object value)
        {
            keyValueCollection.Add(key, value);
        }
        /// <summary>
        /// 删除键值对
        /// </summary>
        /// <param name="key">Key</param>
        public void Remove(string key)
        {
            keyValueCollection.Remove(key);
        }
        /// <summary>
        /// 清除所有键值对
        /// </summary>
        public void Clear()
        {
            keyValueCollection.Clear();
        }
        /// <summary>
        /// 所引器，根据Key返回一个Object类型的值
        /// </summary>
        /// <param name="key">Key</param>
        /// <returns>Value</returns>
        public object this[string key]
        {
            get { return keyValueCollection.ContainsKey(key) ? keyValueCollection[key] : null; }
            set { keyValueCollection[key] = value; }
        }
        public Dictionary<String, Object> ToDictionary()
        {
            return keyValueCollection;
        }

        #region /* Serializable */

        protected KeyValueObject(SerializationInfo info, StreamingContext context)
        {
            var reg = new Regex(@"\[Date\((-?\d+)\)\]");

            foreach (var entry in info)
            {
                Match n = reg.Match(entry.Value.ToString());
                string name = entry.Name;
                object val = entry.Value;

                if (n.Success)
                {
                    try
                    {
                        val = new DateTime(long.Parse(n.Groups[1].Value));
                    }
                    catch
                    {
                        val = entry.Value;
                    }
                }

                keyValueCollection.Add(name, val);
            }
        }

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            foreach (string k in keyValueCollection.Keys)
            {
                object v = keyValueCollection[k];
                Type vType = v == null ? typeof(object) : v.GetType();

                if (vType == typeof(DateTime))
                {
                    info.AddValue(k, String.Format(@"[Date({0})]", ((DateTime)v).Ticks), typeof(string));
                }
                else
                {
                    info.AddValue(k, v, vType);
                }
            }
        }

        #endregion

        public static List<KeyValueObject> KeyValueObjectListWithDataReader(System.Data.IDataReader dataReader)
        {
            List<KeyValueObject> kvList = new List<KeyValueObject>();

            while (dataReader.Read())
            {
                var kvObject = new KeyValueObject();

                for (int i = 0; i < dataReader.FieldCount; i++)
                {
                    kvObject.Set(dataReader.GetName(i), dataReader.GetValue(i));
                }

                kvList.Add(kvObject);
            }

            return kvList;
        }

        public static IEnumerable<KeyValueObject> KeyValueObjectListWithDataTable(System.Data.DataTable dataTable)
        {
            for (int i = 0; i < dataTable.Rows.Count; i++)
            {
                var kvObject = new KeyValueObject();

                for (int j = 0; j < dataTable.Columns.Count; j++)
                {
                    kvObject.Set(dataTable.Columns[j].ColumnName, dataTable.Rows[i][j]);
                }

                yield return kvObject;
            }
        }
        /// <summary>
        /// 将kvObject2中的键值复制到kvObject1
        /// </summary>
        /// <param name="kvObject1"></param>
        /// <param name="kvObject2"></param>
        public static void Copy(KeyValueObject kvObject1, KeyValueObject kvObject2)
        {
            foreach (string key in kvObject2.Keys)
            {
                kvObject1.Set(key, kvObject2[key]);
            }
        }
    }
}
